package com.gt.quality.system.service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.batch.MybatisBatch;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.MybatisBatchUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.gt.quality.base.BusinessSelfException;
import com.gt.quality.base.pojo.BaseLimitRequest;

import cn.hutool.core.collection.CollUtil;

/**
 * @author Administrator
 */
@SuppressWarnings("unused")
public interface GTBaseService<T> extends IService<T> {

    String DEFAULT_TIME_KEY = "create_time";

    String DEFAULT_LAMBDA_TIME_KEY = "createTime";

    String DEFAULT_LOGIC_KEY = "delFlag";

    int ASC = 1;

    int DESC = 2;

    /**
     * Description: 分页对象构建
     *
     * @author: makeJava
     */
    default IPage<T> getByPageParam(BaseLimitRequest<T> param) {
        long pageIndex = param.getPageIndex();
        long pageSize = param.getPageSize();
        return new Page<>(pageIndex, pageSize);
    }

    /**
     * Description: 分页对象构建
     *
     * @author: makeJava
     */
    default IPage<T> getByPageParam(long pageIndex, long pageSize) {
        return new Page<>(pageIndex, pageSize);
    }

    /**
     * 构建整张表的全属性自适应的搜索条件-V1
     *
     * @param thisObj      thisObj
     * @param limitRequest limitRequest
     * @return QueryWrapper
     */
    default QueryWrapper<T> queryWrapperBuilder(JSONObject thisObj, BaseLimitRequest<T> limitRequest) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 构建字段级条件构造器--自适应
        buildQueryConditions(queryWrapper, thisObj, null, limitRequest.getExcludeCol());
        // 构建时间级条件构造器--自适应
        addTimeFilters(queryWrapper, limitRequest);
        // 构建排序条件构造器--自适应
        addOrderByClause(queryWrapper, limitRequest);
        return queryWrapper;
    }

    /**
     * 构建整张表的全属性自适应的搜索条件-V2 支持字段过滤
     *
     * @param thisObj      thisObj
     * @param limitRequest limitRequest
     * @return QueryWrapper
     */
    default QueryWrapper<T> queryWrapperBuilder(JSONObject thisObj, BaseLimitRequest<T> limitRequest,
                                                List<String> excludeCol) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 构建字段级条件构造器--自适应
        buildQueryConditions(queryWrapper, thisObj, excludeCol, limitRequest.getExcludeCol());
        // 构建时间级条件构造器--自适应
        addTimeFilters(queryWrapper, limitRequest);
        // 构建排序条件构造器--自适应
        addOrderByClause(queryWrapper, limitRequest);
        return queryWrapper;
    }

    private void buildQueryConditions(QueryWrapper<T> queryWrapper, JSONObject thisObj, List<String> excludeCol, Map<String, String> handleCol) {
        if (thisObj == null) {
            return;
        }
        Set<Map.Entry<String, Object>> entries = thisObj.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            String key = entry.getKey();
            if (handleCol != null && handleCol.containsKey(key)) {
                String s = handleCol.get(key);
                switch (s) {
                    case "EQ":
                        String columnEq = convertToSnakeCase(key);
                        Object valueEq = entry.getValue();
                        queryWrapper.eq(getValueIsBoolean(valueEq), columnEq, valueEq);
                        break;
                    case "LIKE":
                        String columnLike = convertToSnakeCase(key);
                        Object valueLike = entry.getValue();
                        queryWrapper.like(getValueIsBoolean(valueLike), columnLike, valueLike);
                        break;
                }
                continue;
            }
            if (key.equals(DEFAULT_LOGIC_KEY)) {
                continue;
            }
            if (CollUtil.isNotEmpty(excludeCol) && excludeCol.contains(key)) {
                continue;
            }
            String column = convertToSnakeCase(key);
            Object value = entry.getValue();
            if (value instanceof String) {
                queryWrapper.like(getValueIsBoolean(value), column, value);
            } else {
                queryWrapper.eq(getValueIsBoolean(value), column, value);
            }
        }
    }

    private void addTimeFilters(QueryWrapper<T> queryWrapper, BaseLimitRequest<T> limitRequest) {
        LocalDateTime beginTime = limitRequest.getBeginTime();
        LocalDateTime endTime = limitRequest.getEndTime();
        // 默认使用排序的字段作为时间
        String selectByTimeKeyName = limitRequest.getSelectByTimeKeyName();
        if (StringUtils.isBlank(selectByTimeKeyName)) {
            selectByTimeKeyName = DEFAULT_TIME_KEY;
        }
        if (beginTime != null) {
            queryWrapper.ge(getValueIsBoolean(beginTime), selectByTimeKeyName, beginTime);
        }
        if (endTime != null) {
            queryWrapper.le(getValueIsBoolean(endTime), selectByTimeKeyName, endTime);
        }
    }

    private void addOrderByClause(QueryWrapper<T> queryWrapper, BaseLimitRequest<T> limitRequest) {
        if (limitRequest.isNeedOrderBy()) {
            switch (limitRequest.getOrderByMethod()) {
                case ASC:
                    queryWrapper.orderByAsc(limitRequest.getOrderByKeyName());
                    break;
                case DESC:
                    queryWrapper.orderByDesc(limitRequest.getOrderByKeyName());
                    break;
                default:
                    queryWrapper.orderByDesc(DEFAULT_TIME_KEY);
            }
        }
    }

    private String convertToSnakeCase(String key) {
        StringBuilder column = new StringBuilder();
        char[] chars = key.toCharArray();
        for (char aChar : chars) {
            if (Character.isUpperCase(aChar)) {
                column.append("_");
            }
            column.append(Character.toLowerCase(aChar));
        }
        return column.toString();
    }

    default boolean getValueIsBoolean(Object object) {
        if (object instanceof String) {
            return StringUtils.isNotEmpty((CharSequence) object);
        }
        return !ObjectUtils.isEmpty(object);
    }

    /**
     * 构建整张表的全属性自适应的搜索条件-V2
     *
     * @param thisObj      thisObj
     * @param limitRequest limitRequest
     * @return QueryWrapper
     */
    default LambdaQueryWrapper<T> lambdaQueryWrapperBuilder(T thisObj, BaseLimitRequest<T> limitRequest) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.setEntity(thisObj);
        return queryWrapper;
    }

    /**
     * 获取ORM的Session工厂
     *
     * @return SqlSessionFactory
     */
    SqlSessionFactory getSqlSessionFactory();

    /**
     * 获取ORM的最终实例Mapper
     *
     * @return Mapper
     */
    Class<?> getThisMapperClass();

    /**
     * 获取Spring的事务管理器
     *
     * @return TransactionTemplate
     */
    TransactionTemplate getSpringTx();

    /**
     * 批量新增V2 支持版本：3.5.4 +
     *
     * @param list list
     */
    default void enhancedBatchInsertion(List<T> list) {
        MybatisBatch<T> mybatisBatch = new MybatisBatch<>(getSqlSessionFactory(), list);
        MybatisBatch.Method<T> method = new MybatisBatch.Method<>(getThisMapperClass());
        mybatisBatch.execute(method.insert());
    }

    /**
     * 批量新增V3 支持版本：3.5.4 + 事务支持
     *
     * @param list list
     */
    @SuppressWarnings("unused")
    default void transactionBatchInsertion(List<T> list) {
        TransactionTemplate springTx = getSpringTx();
        springTx.execute((TransactionCallback<List<BatchResult>>) status -> {
            MybatisBatch.Method<T> mapperMethod = new MybatisBatch.Method<>(getThisMapperClass());
            // 执行批量插入
            MybatisBatchUtils.execute(getSqlSessionFactory(), list, mapperMethod.insert());
            throw new BusinessSelfException("出错了");
        });
    }

    default QueryWrapper<T> forQueryWhere(T entity) {
        JSONObject thisObj = JSONObject.from(entity);
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 构建字段级条件构造器--自适应
        buildQueryConditions(queryWrapper, thisObj, null, null);
        return queryWrapper;
    }
}
